function squaredMagnitude(vec) {
	return vec[0] * vec[0] + vec[1] * vec[1];
}

function length(vec) {
	return Math.sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
}

function dist(left, right) {
	return length(sub(left, right));
}

function det(left, right) {
	return left[0] * right[1] - left[1] * right[0];
}

function dot(left, right) {
	return left[0] * right[0] + left[1] * right[1];
}

function scale(sc, vec) {
	var ret = [];
	for (var i = 0; i < vec.length; i++) {
		ret[i] = vec[i] * sc;
	}
	return ret;
}

function add(left, right) {
	var ret = [];
	for (var i = 0; i < left.length; i++) {
		ret[i] = left[i] + right[i];
	}
	return ret;
}

function sub(left, right) {
	return add(left, scale(-1, right));
}

function cross(left, right) {
	return -(left[0] * right[1] - left[1] * right[0]);
}

function transform(mat, vec) {
	return [mat[0][0] * vec[0] + mat[0][1] * vec[1], mat[1][0] * vec[0] + mat[1][1] * vec[1]];
}

function rotationMatrix(angle) {
	var cos = Math.cos(angle);
	var sin = Math.sin(angle);
	return [[cos, -sin], [sin, cos]];
}

function rotate(vec, angle) {
	return transform(rotationMatrix(angle), vec);
}

function normalize(vec, v) {
	var m = Math.sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
	if (m < 0.001) vec[0] = v;
	else {
		v /= m;
		vec[0] *= v;
		vec[1] *= v;
	}
}

var sliders = new Array();
function makeSlider(label, slidefun, slideparams, linkedParam)
{
	if (typeof(label)=="undefined") label="nolabel";
	if (typeof(slideparams)=="undefined") slideparams={};

	if (typeof(slideparams.value)=="undefined") slideparams.value = params[linkedParam];

	var outer = $("<div />").addClass("inset").appendTo("#controls");
	$("<span \>").text(label+":").addClass("numlabel").appendTo(outer);

	var inp = $("<input \>").addClass("numinput").attr('type','number').appendTo(outer);
	var sdi = $("<div \>").addClass("slidermarg").appendTo(outer);
	sdi.slider(slideparams).bind("slide",
			function( event, ui ) {
				inp.val( ui.value );
				slidefun(ui.value)
			} );
	inp.val(slideparams.value);
	slidefun(slideparams.value);

	sliders[sliders.length] = {
		input: inp,
		slider: sdi,
		param: linkedParam,
	};
}

function angleBetween(v0, v1) {
	var cos = dot(v0, v1) / length(v0) / length(v1);
	cos = Math.min(1.0, Math.max(-1.0, cos));
	return Math.acos(cos);
}

function turn(tgt, vec, away) {
	var angle = angleBetween(tgt, vec);

	if (angle > params.maxTurn) { angle = params.maxTurn; }
	if (cross(tgt, vec) < 0) { angle = -angle; }
	if (away) angle = -angle;

	return rotate(vec, angle);
}

function turnAway(tgt, vec) {
	return turn(tgt, vec, true);
}

function turnToward(tgt, vec) {
	return turn(tgt, vec, false);
}

// convert integer to string with commas
function formatNumber(val) {
	var str = val.toString();
	if (str.length > 3)
		return addCommas(str.substr(0, str.length - 3)) + "," + str.substr(str.length - 3);
	return str;
}

// convert milliseconds to sss.m
function formatTime(tm) {
	var str = (Math.floor(tm / 1000)).toString(10);
	var d = Math.floor((tm % 1000) / 100);
	return str + "." + d;
}

function normalDecompose(d, normal) {
    var negnormal = scale(-1, normal);
    var dotn = dot(d, negnormal);
    var ncomp = scale(dotn, negnormal);
    var tcomp = sub(d, ncomp);
    return [dotn, ncomp, tcomp];
}

